package saucaca.Youtube;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import javax.xml.parsers.FactoryConfigurationError;

import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import saucaca.Video.FullScreenVideoStreamView;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.net.Uri;
import android.preference.PreferenceManager;
import android.util.Log;

import com.lemon.kenhnhacvn.BaseEngine;

public class YouTubeUtility {

    /**
     * Retrieve the latest video in the specified playlist.
     *
     * @param pPlaylistId the id of the playlist for which to retrieve the latest video id
     * @return the video id of the latest video, null if something goes wrong
     * @throws IOException
     * @throws ClientProtocolException
     * @throws FactoryConfigurationError
     */
    public static String queryLatestPlaylistVideo(PlaylistId pPlaylistId)
            throws IOException, ClientProtocolException,
            FactoryConfigurationError {

        String lVideoId = null;

        HttpClient lClient = new DefaultHttpClient();

        HttpGet lGetMethod = new HttpGet(FullScreenVideoStreamView.YOUTUBE_PLAYLIST_ATOM_FEED_URL +
                pPlaylistId.getId() + "?v=2&max-results=50&alt=json");

        HttpResponse lResp = null;

        lResp = lClient.execute(lGetMethod);

        ByteArrayOutputStream lBOS = new ByteArrayOutputStream();
        String lInfoStr = null;
        JSONObject lYouTubeResponse = null;

        try {

            lResp.getEntity().writeTo(lBOS);
            lInfoStr = lBOS.toString("UTF-8");
            lYouTubeResponse = new JSONObject(lInfoStr);

            JSONArray lEntryArr = lYouTubeResponse.getJSONObject("feed").getJSONArray("entry");
            JSONArray lLinkArr = lEntryArr.getJSONObject(lEntryArr.length() - 1).getJSONArray("link");
            for (int i = 0; i < lLinkArr.length(); i++) {
                JSONObject lLinkObj = lLinkArr.getJSONObject(i);
                ;
                String lRelVal = lLinkObj.optString("rel", null);
                if (lRelVal != null && lRelVal.equals("alternate")) {

                    String lUriStr = lLinkObj.optString("href", null);
                    Uri lVideoUri = Uri.parse(lUriStr);
                    lVideoId = lVideoUri.getQueryParameter("v");
                    break;
                }
            }
        } catch (IllegalStateException e) {
            Log.i(YouTubeUtility.class.getSimpleName(), "Error retrieving content from YouTube", e);
        } catch (IOException e) {
            Log.i(YouTubeUtility.class.getSimpleName(), "Error retrieving content from YouTube", e);
        } catch (JSONException e) {
            Log.i(YouTubeUtility.class.getSimpleName(), "Error retrieving content from YouTube", e);
        }

        return lVideoId;
    }


    /**
     * Calculate the YouTube URL to load the video.  Includes retrieving a token that YouTube
     * requires to play the video.
     *
     * @param pYouTubeFmtQuality quality of the video.  17=low, 18=high
     * @param bFallback          whether to fallback to lower quality in case the supplied quality is not available
     * @param pYouTubeVideoId    the id of the video
     * @return the url string that will retrieve the video
     * @throws IOException
     * @throws ClientProtocolException
     * @throws UnsupportedEncodingException
     */
    public static String calculateYouTubeUrl(String pYouTubeFmtQuality, boolean pFallback,
                                             String pYouTubeVideoId) throws IOException,
            ClientProtocolException, UnsupportedEncodingException {

        String lUriStr = null;
        HttpClient lClient = new DefaultHttpClient();

        HttpGet lGetMethod = new HttpGet(FullScreenVideoStreamView.YOUTUBE_VIDEO_INFORMATION_URL +pYouTubeVideoId+"&el=embedded-format=5");

        HttpResponse lResp = null;

        lResp = lClient.execute(lGetMethod);

        ByteArrayOutputStream lBOS = new ByteArrayOutputStream();
        String lInfoStr = null;

        lResp.getEntity().writeTo(lBOS);
        lInfoStr = new String(lBOS.toString("UTF-8"));
//        Log.i("calculateYouTubeUrl",lInfoStr);
        String[] lArgs = lInfoStr.split("&");
        
        Map<String, String> lArgMap = new HashMap<String, String>();
        for (int i = 0; i < lArgs.length; i++) {
            String[] lArgValStrArr = lArgs[i].split("=");
            if (lArgValStrArr != null) {
                if (lArgValStrArr.length >= 2) {
                    lArgMap.put(lArgValStrArr[0], URLDecoder.decode(lArgValStrArr[1]));
                }
            }
        }

        //Find out the URI string from the parameters

        //Populate the list of formats for the video
        String lFmtList = URLDecoder.decode(lArgMap.get("fmt_list"));
        ArrayList<Format> lFormats = new ArrayList<Format>();
        if (null != lFmtList) {
            String lFormatStrs[] = lFmtList.split(",");

            for (String lFormatStr : lFormatStrs) {
                Format lFormat = new Format(lFormatStr);
                lFormats.add(lFormat);
            }
        }

        //Populate the list of streams for the video
        String lStreamList = lArgMap.get("url_encoded_fmt_stream_map");
        if (null != lStreamList) {
            String lStreamStrs[] = lStreamList.split(",");
            ArrayList<VideoStream> lStreams = new ArrayList<VideoStream>();
            for (String lStreamStr : lStreamStrs) {
                VideoStream lStream = new VideoStream(lStreamStr);
//                BaseEngine.showLogformLongString("youtube_url",lStream.getUrl());
                lStreams.add(lStream);
            }

            //Search for the given format in the list of video formats
            // if it is there, select the corresponding stream
            // otherwise if fallback is requested, check for next lower format
            int lFormatId = Integer.parseInt(pYouTubeFmtQuality);

            Format lSearchFormat = new Format(lFormatId);
            while (!lFormats.contains(lSearchFormat) && pFallback) {
                int lOldId = lSearchFormat.getId();
                int lNewId = getSupportedFallbackId(lOldId);

                if (lOldId == lNewId) {
                    break;
                }
                lSearchFormat = new Format(lNewId);
            }

            int lIndex = lFormats.indexOf(lSearchFormat);
            if (lIndex >= 0) {
                VideoStream lSearchStream = lStreams.get(lIndex);
                lUriStr = lSearchStream.getUrl();
            }

        }
        //Return the URI string. It may be null if the format (or a fallback format if enabled)
        // is not found in the list of formats for the video
        return lUriStr;
    }

    public static boolean hasVideoBeenViewed(Context pCtxt, String pVideoId) {
        SharedPreferences lPrefs = PreferenceManager.getDefaultSharedPreferences(pCtxt);

        String lViewedVideoIds = lPrefs.getString("com.keyes.screebl.lastViewedVideoIds", null);

        if (lViewedVideoIds == null) {
            return false;
        }

        String[] lSplitIds = lViewedVideoIds.split(";");
        if (lSplitIds == null || lSplitIds.length == 0) {
            return false;
        }

        for (int i = 0; i < lSplitIds.length; i++) {
            if (lSplitIds[i] != null && lSplitIds[i].equals(pVideoId)) {
                return true;
            }
        }

        return false;

    }

    public static void markVideoAsViewed(Context pCtxt, String pVideoId) {

        SharedPreferences lPrefs = PreferenceManager.getDefaultSharedPreferences(pCtxt);

        if (pVideoId == null) {
            return;
        }

        String lViewedVideoIds = lPrefs.getString("com.keyes.screebl.lastViewedVideoIds", null);

        if (lViewedVideoIds == null) {
            lViewedVideoIds = "";
        }

        String[] lSplitIds = lViewedVideoIds.split(";");
        if (lSplitIds == null) {
            lSplitIds = new String[]{};
        }

        // make a hash table of the ids to deal with duplicates
        Map<String, String> lMap = new HashMap<String, String>();
        for (int i = 0; i < lSplitIds.length; i++) {
            lMap.put(lSplitIds[i], lSplitIds[i]);
        }

        // recreate the viewed list
        String lNewIdList = "";
        Set<String> lKeys = lMap.keySet();
        Iterator<String> lIter = lKeys.iterator();
        while (lIter.hasNext()) {
            String lId = lIter.next();
            if (!lId.trim().equals("")) {
                lNewIdList += lId + ";";
            }
        }

        // add the new video id
        lNewIdList += pVideoId + ";";

        Editor lPrefEdit = lPrefs.edit();
        lPrefEdit.putString("com.keyes.screebl.lastViewedVideoIds", lNewIdList);
        lPrefEdit.commit();

    }

    public static int getSupportedFallbackId(int pOldId) {
        final int lSupportedFormatIds[] = {13,  //3GPP (MPEG-4 encoded) Low quality
                17,  //3GPP (MPEG-4 encoded) Medium quality
                18,  //MP4  (H.264 encoded) Normal quality
                22,  //MP4  (H.264 encoded) High quality
                37   //MP4  (H.264 encoded) High quality
        };
        int lFallbackId = pOldId;
        for (int i = lSupportedFormatIds.length - 1; i >= 0; i--) {
            if (pOldId == lSupportedFormatIds[i] && i > 0) {
                lFallbackId = lSupportedFormatIds[i - 1];
            }
        }
        return lFallbackId;
    }
}
